package com.cz.video.web.controller.website;


import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.dev33.satoken.annotation.SaIgnore;
import cn.hutool.core.collection.CollUtil;
import com.cz.video.common.annotation.LegalValidate;
import com.cz.video.common.annotation.Log;
import com.cz.video.common.annotation.RateLimiter;
import com.cz.video.common.annotation.RepeatSubmit;
import com.cz.video.common.core.controller.BaseController;
import com.cz.video.common.core.domain.PageQuery;
import com.cz.video.common.core.domain.R;
import com.cz.video.common.core.page.TableDataInfo;
import com.cz.video.common.core.validate.EditGroup;
import com.cz.video.common.enums.BusinessType;
import com.cz.video.common.exception.ServiceException;
import com.cz.video.common.helper.LoginHelper;
import com.cz.video.common.utils.StringUtils;
import com.cz.video.common.utils.ValidatorUtils;
import com.cz.video.common.utils.spring.SpringUtils;
import com.cz.video.common.vod.constants.VodConstants;
import com.cz.video.common.vod.dto.VodCallBack;
import com.cz.video.common.vod.dto.VodCallbackEvent;
import com.cz.video.common.vod.dto.VodPlayAuth;
import com.cz.video.common.vod.dto.VodUploadAuth;
import com.cz.video.common.vod.service.VodService;
import com.cz.video.website.domain.WebsiteVideo;
import com.cz.video.website.domain.bo.WebsiteHistoryBo;
import com.cz.video.website.domain.bo.WebsiteVideoBo;
import com.cz.video.website.domain.vo.WebsiteVideoVo;
import com.cz.video.website.service.IWebsiteVideoService;
import com.cz.video.website.service.WebsiteHistoryService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.validation.constraints.NotNull;

/**
 * <p>
 * 电影视频表 前端控制器
 * </p>
 *
 * @author 洪圆胜
 * @since 2023-10-15
 */
@Tag(name = "视频播放管理")
@RestController
@Validated
@Slf4j
@RequiredArgsConstructor
@RequestMapping("/website/video")
public class WebsiteVideoController extends BaseController {

    private final IWebsiteVideoService websiteVideoService;
    private final VodService vodService;
    private final WebsiteHistoryService historyService;


    @SaCheckPermission("website:video:add")
    @Log(title = "添加视频", businessType = BusinessType.INSERT)
    @LegalValidate
    @RepeatSubmit
    @Operation(summary = "添加视频")
    @PostMapping("")
    public R<VodUploadAuth> add(@RequestBody @Validated WebsiteVideoBo websiteVideo){
        //获取vod上传凭证
        websiteVideo.setUploaderId(LoginHelper.getUserId());
        VodUploadAuth auth = vodService.createUploadVideo(websiteVideo.getTitle(), websiteVideo.getFileName());
        websiteVideo.setVid(auth.getVid());
        websiteVideoService.addVideo(websiteVideo);
        return R.ok(auth);
    }

    @SaCheckPermission("website:video:edit")
    @Log(title = "修改视频", businessType = BusinessType.UPDATE)
    @Operation(summary = "修改视频")
    @LegalValidate
    @PutMapping("")
    public R<VodUploadAuth> edit(@RequestBody WebsiteVideoBo websiteVideo){
        ValidatorUtils.validate(websiteVideo, EditGroup.class);

        //获取vod上传凭证
        VodUploadAuth auth =null;
        int res = websiteVideoService.update(websiteVideo);
        if (res==0)
            return R.fail();
        if (StringUtils.isNoneBlank(websiteVideo.getFileName())) {
            auth = vodService.createUploadVideo(websiteVideo.getTitle(), websiteVideo.getFileName());
            websiteVideo.setVid(auth.getVid());
        }
        return R.ok(auth);
    }

    @SaCheckPermission("website:video:audit")
    @Log(title = "审核视频", businessType = BusinessType.INSERT)
    @RepeatSubmit
    @Operation(summary = "审核视频")
    @PostMapping("/audit/{videoId}")
    public R<Void> audit(@PathVariable Long videoId,@NotNull(message = "没有审核结果") Boolean isPass,
                         String auditResult){
        return toAjax(websiteVideoService.audit(videoId, isPass,auditResult));
    }

    @SaCheckPermission("website:video:audit")
    @Log(title = "上下架视频", businessType = BusinessType.INSERT)
    @Operation(summary = "上下架视频")
    @PostMapping("/editStatus/{videoId}")
    public R<Void> editStatus(@PathVariable Long videoId,@NotNull(message = "没有选择是否上架") Boolean isOnline){
        return toAjax(websiteVideoService.updateStatus(videoId, isOnline));
    }


    @SaCheckPermission("website:video:delete")
    @Log(title = "删除视频", businessType = BusinessType.DELETE)
    @Operation(summary = "删除视频")
    @DeleteMapping("/{id}")
    public R<Void> delete(@PathVariable Long[] id){
        return toAjax((websiteVideoService.deleteSelfById(id)));
    }

    @Log(title = "删除自己的视频", businessType = BusinessType.DELETE)
    @Operation(summary = "删除自己的视频")
    @DeleteMapping("/self/{id}")
    public R<Void> deleteSelf(@PathVariable Long[] id){
        return toAjax((websiteVideoService.deleteSelfById(id)));
    }

    @SaIgnore
    @RateLimiter
    @Operation(summary = "查看视频")
    @GetMapping("/{id}")
    public R<WebsiteVideoVo> view(@PathVariable Long id){
        historyService.reflush(LoginHelper.getUserId());
        WebsiteVideoVo websiteVideo = websiteVideoService.getById(id);
        //设置播放凭证
        if (websiteVideo!=null) {
            websiteVideo.setClickCount(websiteVideo.getClickCount()+1);
            websiteVideoService.setCover(CollUtil.newArrayList(websiteVideo));
            WebsiteHistoryBo historyBo = new WebsiteHistoryBo();
            historyBo.setVideoId(id);
            historyService.addCache(historyBo);
            VodPlayAuth playAuth = vodService.getVideoPlayAuth(websiteVideo.getVid());
            websiteVideo.setPlayAuth(playAuth);
        }
        return R.ok(websiteVideo);
    }

    @SaIgnore
    @RateLimiter
    @Operation(summary = "获取播放凭证")
    @GetMapping("/playAuth/{id}")
    public R<VodPlayAuth> getPlayAuth(@PathVariable Long id){
        WebsiteVideoVo websiteVideo = websiteVideoService.getById(id);
        VodPlayAuth playAuth;
        //设置播放凭证
        if (websiteVideo!=null) {
            WebsiteHistoryBo historyBo = new WebsiteHistoryBo();
            historyBo.setVideoId(id);
            historyService.addCache(historyBo);
            playAuth = vodService.getVideoPlayAuth(websiteVideo.getVid());
            return R.ok(playAuth);
        }else throw new ServiceException("该视频不存在");
    }


    @SaIgnore
    @Operation(summary = "分页查询视频")
    @GetMapping("/list")
    public TableDataInfo<WebsiteVideoVo> page(WebsiteVideoBo websiteVideo, PageQuery pageQuery){

        return websiteVideoService.page(websiteVideo,pageQuery);
    }

    @SaIgnore
    @Operation(summary = "获取热门视频")
    @GetMapping("/hotList")
    public TableDataInfo<WebsiteVideoVo> hotPage(PageQuery pageQuery){
        return websiteVideoService.hotPage(pageQuery);
    }

    @SaIgnore
    @Operation(summary = "获取推荐视频")
    @GetMapping("/recommendedList/{videoId}")
    public TableDataInfo<WebsiteVideoVo> recommendedList(@PathVariable Long videoId, PageQuery pageQuery){
        return websiteVideoService.pageRecommended(videoId,pageQuery);
    }


    @Operation(summary = "视频记录心跳包")
    @PostMapping("/heartbeat")
    public R<Void> heartbeat(@RequestBody WebsiteHistoryBo history) {
        return toAjax(historyService.addCache(history));
    }



    /**
     * 点赞
     *
     * @param sourceId
     * @return
     */
    @Log(title = "点赞", businessType = BusinessType.INSERT)
    @Operation(summary = "点赞")
    @RateLimiter(time = 10,count = 10)
    @PostMapping("/like/{sourceId}")
    public R<Void> like(@PathVariable("sourceId")@Parameter(description = "源id") Long sourceId) {
        return toAjax(websiteVideoService.like(sourceId));
    }

    /**
     * vod上传成功回调处理
     *
     * @param callBack 回调参数,
     * @return R
     */
    @SneakyThrows
    @Operation(summary = "上传成功回调处理")
    @SaIgnore
    @PostMapping("/aliyunCallback")
    public R<Void> callback(@RequestBody VodCallBack callBack, HttpServletRequest request) {
        //校验请求合法性
        vodService.checkCallbackValid(request);
        WebsiteVideo video = websiteVideoService.getByVid(callBack.getVideoId());
        if (video == null) {
            throw new ServiceException("视频不存在");
        }
        //上传成功
        if (VodConstants.SUCCESS.equals(callBack.getStatus())){
            //这里就只更新上传状态，并且发一下事件，因为在回调中无法查询出元数据
            video.setUploadStatus(VodConstants.UPLOAD_SUCCESS);
            websiteVideoService.updateUploadStatus(video);
            //发布事件
            VodCallbackEvent callbackEvent = VodCallbackEvent.builder().videoId(video.getVideoId()).vid(callBack.getVideoId())
                    .fileUrl(callBack.getFileUrl()).size(callBack.getSize()).build();
            SpringUtils.context().publishEvent(callbackEvent);
            log.info("上传成功回调事件资源id[{}],vid：{}",video.getVideoId(),callBack.getVideoId());
        }

        //上传失败
        if (VodConstants.FAIL.equals(callBack.getStatus())){
            video.setUploadStatus(VodConstants.UPLOAD_FAILURE);
            websiteVideoService.updateUploadStatus(video);
            log.info("上传失败回调事件资源id[{}],vid：{}",video.getVideoId(),callBack.getVideoId());
        }

        return R.ok();
    }
}
